/* This example demostrates physics actions, like applying impulses and forces
 * to a body.
 *
 * There are two ways of interacting with bodies. One is using the wanted
 * action in a program. E.g.:
 *
 * action: PHYSICS_VEL_SET 0 -200 0;
 * target: "part_name";
 *
 * The other way is via script. The same action described above would be
 * physics_set_velocity(PART:"part_name", 0, -200, 0);
 *
 * This a very extensive example, because it illustrate the usage of all
 * the possible actions in the both ways.
 *
 * It can be tested with edje_player slave mode
 * $ edje_player -S -p physics_actions.edj
 *
 * signal up impulse   -> will throw both balls up
 * signal down impulse   -> will throw both balls down
 * signal left impulse -> will throw blue ball to the left
 * signal right impulse -> will throw red ball to the right
 * signal clockwise impulse -> will roll blue ball in clockwise
 * signal counterclockwise impulse -> will roll blue ball in counterclockwise
 * signal up force -> will apply a force up in blue ball
 * signal down force -> will apply a force down in blue ball
 * signal left force -> will apply a force left in blue ball
 * signal right force -> will apply a force right in blue ball
 * signal clockwise torque -> will apply a clockwise torque in blue ball
 * signal counterclockwise torque -> will apply a counterclockwise torque
 *                                   in blue ball
 * signal clear force -> will clear all forces applied over blue ball
 * signal up velocity -> will set a velocity up in blue ball
 * signal down velocity -> will set a velocity down in blue ball
 * signal left velocity -> will set a velocity left in blue ball
 * signal right velocity -> will set a velocity right in blue ball
 * signal clockwise velocity -> will set a clockwise velocity in blue ball
 * signal counterclockwise velocity -> will set a counterclockwise velocity
 *                                   in blue ball
 * signal stop velocity -> will stop the blue ball
 * signal clockwise rotation -> will rotate blue ball 90o degrees clockwise
 * signal counterclockwise rotation -> will rotate blue ball 90o degrees
 *                                     counterclockwise
 *
 * message 1 FLOAT_SET 3 50 -100 0 -> apply an impulse on blue ball with
 *    x = 50, y = -100, z = 0, for example
 * message 2 FLOAT_SET 3 0 0 8.2 -> apply a torque impulse on blue ball with
 *    x = 4, y = 0, z = 0.8, for example
 * message 3 FLOAT_SET 3 80 100.4 0 -> apply a force on blue ball with
 *    x = 80, y = 100.4, z = 0, for example
 * message 4 FLOAT_SET 3 0 0 -5.6 -> apply a torque on blue ball with
 *    x = 0, y = 0, z = -5.6, for example
 * message 5 STRING "blue_circle" -> clear all forces of part.
 *    It will clear all forces (linear and torque) over "blue_circle",
 *    for example.
 * message 6 STRING "blue_circle" -> return a message with all forces applied
 *    over the part.
 * message 7 STRING "blue_circle" -> return a message with all torques applied
 *    over the part.
 * message 8 FLOAT_SET 3 300 -103.2 0 -> set linear velocity of the blue ball
 *    with x = 300, y = -103.2, z = 150, for example
 * message 9 STRING "blue_circle" -> return a message with part's linear
 *    velocity.
 * message 10 FLOAT_SET 3 0 0 150 -> set angular velocity of the blue ball
 *    with x = 0, y = 0, z = 150, for example
 * message 11 STRING "blue_circle" -> return a message with part's angular
 *    velocity.
 * message 12 STRING "blue_circle" -> stop the part.
 * message 13 FLOAT_SET 4 0.707 0 0 0.707 -> set blue ball rotation with
 *    quaternion w = 0.707, x = 0, y = 0, z = 0.707
 * message 14 STRING "blue_circle" -> return a message with part's rotation
 */

#define ID_IMPULSE (1)
#define ID_TORQUE_IMPULSE (2)
#define ID_FORCE (3)
#define ID_TORQUE (4)
#define ID_FORCES_CLEAR (5)
#define ID_FORCES_GET (6)
#define ID_TORQUES_GET (7)
#define ID_VEL_SET (8)
#define ID_VEL_GET (9)
#define ID_ANG_VEL_SET (10)
#define ID_ANG_VEL_GET (11)
#define ID_STOP (12)
#define ID_ROT_SET (13)
#define ID_ROT_GET (14)

collections {

   images {
      image: "bubble-blue.png" COMP;
   }

   group {
      name: "example_group";

      script {
         public message(Msg_Type:type, id, ...) {
            if ((id == ID_IMPULSE) && (type == MSG_FLOAT_SET)) {
               new Float:x, Float:y, Float:z;
               new n = numargs();
               if (n < 5) return;
               x = getfarg(2);
               y = getfarg(3);
               z = getfarg(4);
               physics_impulse(PART:"blue_circle", x, y, z);
            }
            else if ((id == ID_TORQUE_IMPULSE) && (type == MSG_FLOAT_SET)) {
               new Float:x, Float:y, Float:z;
               new n = numargs();
               if (n < 5) return;
               x = getfarg(2);
               y = getfarg(3);
               z = getfarg(4);
               physics_torque_impulse(PART:"blue_circle", x, y, z);
            }
            else if ((id == ID_FORCE) && (type == MSG_FLOAT_SET)) {
               new Float:x, Float:y, Float:z;
               new n = numargs();
               if (n < 5) return;
               x = getfarg(2);
               y = getfarg(3);
               z = getfarg(4);
               physics_force(PART:"blue_circle", x, y, z);
            }
            else if ((id == ID_TORQUE) && (type == MSG_FLOAT_SET)) {
               new Float:x, Float:y, Float:z;
               new n = numargs();
               if (n < 5) return;
               x = getfarg(2);
               y = getfarg(3);
               z = getfarg(4);
               physics_torque(PART:"blue_circle", x, y, z);
            }
            else if ((id == ID_FORCES_CLEAR) && (type == MSG_STRING)) {
               new pid, name[1024];
               getsarg(2, name, sizeof(name));
               pid = get_part_id(name);
               if (!pid) return;
               physics_clear_forces(pid);
            }
            else if ((id == ID_FORCES_GET) && (type == MSG_STRING)) {
               new Float:x, Float:y, Float:z;
               new pid, name[1024];
               getsarg(2, name, sizeof(name));
               pid = get_part_id(name);
               if (!pid) return;
               physics_get_forces(pid, x, y, z);
               send_message(MSG_FLOAT_SET, id, x, y, z);
            }
            else if ((id == ID_TORQUES_GET) && (type == MSG_STRING)) {
               new Float:x, Float:y, Float:z;
               new pid, name[1024];
               getsarg(2, name, sizeof(name));
               pid = get_part_id(name);
               if (!pid) return;
               physics_get_torques(pid, x, y, z);
               send_message(MSG_FLOAT_SET, id, x, y, z);
            }
            else if ((id == ID_VEL_SET) && (type == MSG_FLOAT_SET)) {
               new Float:x, Float:y, Float:z;
               new n = numargs();
               if (n < 5) return;
               x = getfarg(2);
               y = getfarg(3);
               z = getfarg(4);
               physics_set_velocity(PART:"blue_circle", x, y, z);
            }
            else if ((id == ID_VEL_GET) && (type == MSG_STRING)) {
               new Float:x, Float:y, Float:z;
               new pid, name[1024];
               getsarg(2, name, sizeof(name));
               pid = get_part_id(name);
               if (!pid) return;
               physics_get_velocity(pid, x, y, z);
               send_message(MSG_FLOAT_SET, id, x, y, z);
            }
            else if ((id == ID_ANG_VEL_SET) && (type == MSG_FLOAT_SET)) {
               new Float:x, Float:y, Float:z;
               new n = numargs();
               if (n < 5) return;
               x = getfarg(2);
               y = getfarg(3);
               z = getfarg(4);
               physics_set_ang_velocity(PART:"blue_circle", x, y, z);
            }
            else if ((id == ID_ANG_VEL_GET) && (type == MSG_STRING)) {
               new Float:x, Float:y, Float:z;
               new pid, name[1024];
               getsarg(2, name, sizeof(name));
               pid = get_part_id(name);
               if (!pid) return;
               physics_get_ang_velocity(pid, x, y, z);
               send_message(MSG_FLOAT_SET, id, x, y, z);
            }
            else if ((id == ID_STOP) && (type == MSG_STRING)) {
               new pid, name[1024];
               getsarg(2, name, sizeof(name));
               pid = get_part_id(name);
               if (!pid) return;
               physics_stop(pid);
            }
            else if ((id == ID_ROT_SET) && (type == MSG_FLOAT_SET)) {
               new Float:w, Float:x, Float:y, Float:z;
               new n = numargs();
               if (n < 6) return;
               w = getfarg(2);
               x = getfarg(3);
               y = getfarg(4);
               z = getfarg(5);
               physics_set_rotation(PART:"blue_circle", w, x, y, z);
            }
            else if ((id == ID_ROT_GET) && (type == MSG_STRING)) {
               new Float:w, Float:x, Float:y, Float:z;
               new pid, name[1024];
               getsarg(2, name, sizeof(name));
               pid = get_part_id(name);
               if (!pid) return;
               physics_get_rotation(pid, w, x, y, z);
               send_message(MSG_FLOAT_SET, id, w, x, y, z);
            }
         }
      }

      parts {
         part {
            name: "background";
            type: RECT;
            physics_body: NONE;
            description {
               state: "default" 0.0;
               color: 255 255 255 255; /* white */
               rel1.relative: 0.0 0.0;
               rel2.relative: 1.0 1.0;
            }
         }

         part {
            name: "blue_circle";
            type: IMAGE;
            physics_body: RIGID_SPHERE;
            description {
               state: "default" 0.0;
               rel1.relative: 0.35 0.1;
               rel2.relative: 0.55 0.2;
               aspect: 1 1;
               image {
                  normal: "bubble-blue.png";
               }
               physics {
                  restitution: 0.85;
                  friction: 1.0;
               }
            }
         }

         part {
            name: "red_circle";
            type: IMAGE;
            physics_body: RIGID_SPHERE;
            description {
               state: "default" 0.0;
               color: 255 0 0 255; /* light red */
               rel1.relative: 0.65 0.1;
               rel2.relative: 0.85 0.2;
               aspect: 1 1;
               image {
                  normal: "bubble-blue.png";
               }
               physics {
                  restitution: 0.85;
                  friction: 1.0;
               }
            }
         }

         part {
            name: "floor";
            type: RECT;
            physics_body: BOUNDARY_BOTTOM;
            description {
               state: "default" 0.0;
               visible: 0;
               physics {
                  restitution: 0.6;
                  friction: 1.0;
               }
            }
         }

         part {
            name: "right_wall";
            type: RECT;
            physics_body: BOUNDARY_RIGHT;
            description {
               state: "default" 0.0;
               visible: 0;
               physics {
                  restitution: 0.3;
               }
            }
         }

         part {
            name: "left_wall";
            type: RECT;
            physics_body: BOUNDARY_LEFT;
            description {
               state: "default" 0.0;
               visible: 0;
               physics {
                  restitution: 0.3;
               }
            }
         }

         part {
            name: "roof";
            type: RECT;
            physics_body: BOUNDARY_TOP;
            description {
               state: "default" 0.0;
               visible: 0;
               physics {
                  restitution: 0.2;
               }
            }
         }
      }

      programs {

         program {
            name: "impulse_up";
            signal: "up";
            source: "impulse";
            action: PHYSICS_IMPULSE 0 -300 0;
            target: "blue_circle";
            target: "red_circle";
         }

         program {
            name: "impulse_down";
            signal: "down";
            source: "impulse";
            action: PHYSICS_IMPULSE 0 300 0;
            target: "red_circle";
            target: "blue_circle";
         }

         program {
            name: "impulse_left";
            signal: "left";
            source: "impulse";
            action: PHYSICS_IMPULSE -300 0 0;
            target: "blue_circle";
         }

         program {
            name: "impulse_right";
            signal: "right";
            source: "impulse";
            action: PHYSICS_IMPULSE 300 0 0;
            target: "red_circle";
         }

         program {
            name: "impulse_clockwise";
            signal: "clockwise";
            source: "impulse";
            action: PHYSICS_TORQUE_IMPULSE 0 0 4;
            target: "blue_circle";
         }

         program {
            name: "impulse_counterclockwise";
            signal: "counterclockwise";
            source: "impulse";
            action: PHYSICS_TORQUE_IMPULSE 0 0 -4;
            target: "blue_circle";
         }

         program {
            name: "force_up";
            signal: "up";
            source: "force";
            action: PHYSICS_FORCE 0 -300 0;
            target: "blue_circle";
         }

         program {
            name: "force_down";
            signal: "down";
            source: "force";
            action: PHYSICS_FORCE 0 300 0;
            target: "blue_circle";
         }

         program {
            name: "force_left";
            signal: "left";
            source: "force";
            action: PHYSICS_FORCE -300 0 0;
            target: "blue_circle";
         }

         program {
            name: "force_right";
            signal: "right";
            source: "force";
            action: PHYSICS_FORCE 300 0 0;
            target: "blue_circle";
         }

         program {
            name: "torque_clockwise";
            signal: "clockwise";
            source: "torque";
            action: PHYSICS_TORQUE 0 0 4;
            target: "blue_circle";
         }

         program {
            name: "torque_counterclockwise";
            signal: "counterclockwise";
            source: "torque";
            action: PHYSICS_TORQUE 0 0 -4;
            target: "blue_circle";
         }

         program {
            name: "forces_clear";
            signal: "clear";
            source: "force";
            action: PHYSICS_FORCES_CLEAR;
            target: "blue_circle";
         }

         program {
            name: "velocity_up";
            signal: "up";
            source: "velocity";
            action: PHYSICS_VEL_SET 0 -200 0;
            target: "blue_circle";
         }

         program {
            name: "velocity_down";
            signal: "down";
            source: "velocity";
            action: PHYSICS_VEL_SET 0 200 0;
            target: "blue_circle";
         }

         program {
            name: "velocity_left";
            signal: "left";
            source: "velocity";
            action: PHYSICS_VEL_SET -200 0 0;
            target: "blue_circle";
         }

         program {
            name: "velocity_right";
            signal: "right";
            source: "velocity";
            action: PHYSICS_VEL_SET 200 0 0;
            target: "blue_circle";
         }

         program {
            name: "velocity_clockwise";
            signal: "clockwise";
            source: "velocity";
            action: PHYSICS_ANG_VEL_SET 0 0 80;
            target: "blue_circle";
         }

         program {
            name: "velocity_counterclockwise";
            signal: "counterclockwise";
            source: "velocity";
            action: PHYSICS_ANG_VEL_SET 0 0 -80;
            target: "blue_circle";
         }

         program {
            name: "stop";
            signal: "stop";
            source: "velocity";
            action: PHYSICS_STOP;
            target: "blue_circle";
         }

         program {
            name: "rotation_clockwise";
            signal: "clockwise";
            source: "rotation";
            action: PHYSICS_ROT_SET 0.707 0 0 0.707;
            target: "blue_circle";
         }

         program {
            name: "rotation_counterclockwise";
            signal: "counterclockwise";
            source: "rotation";
            action: PHYSICS_ROT_SET 0.707 0 0 -0.707;
            target: "blue_circle";
         }

         program {
            name: "customize";
            signal: "custom";
            script {
               new Float: mass, Float:rest, Float:fric;
               new Float: linear, Float:angular;
               new val;

               custom_state(PART:"red_circle", "default", 0.0);
               set_state_val(PART:"red_circle", STATE_COLOR, 0, 0, 0, 255);
               set_state_val(PART:"red_circle", STATE_PHYSICS_MASS, 4.5);
               set_state_val(PART:"red_circle", STATE_PHYSICS_RESTITUTION, 0.1);
               set_state_val(PART:"red_circle", STATE_PHYSICS_FRICTION, 0.345);
               set_state_val(PART:"red_circle", STATE_PHYSICS_DAMPING, 0.3,
                       0.1);
               set_state_val(PART:"red_circle", STATE_PHYSICS_SLEEP, 34.1,
                       12.83);
               set_state_val(PART:"red_circle", STATE_PHYSICS_LIGHT_ON, 1);
               set_state_val(PART:"red_circle",
                       STATE_PHYSICS_IGNORE_PART_POS, 1);
               set_state_val(PART:"red_circle", STATE_PHYSICS_Z, -40);
               set_state_val(PART:"red_circle", STATE_PHYSICS_DEPTH, 80);
               set_state(PART:"red_circle", "custom", 0.0);

               get_state_val(PART:"red_circle", STATE_PHYSICS_MASS, mass);
               get_state_val(PART:"red_circle", STATE_PHYSICS_RESTITUTION,
                     rest);
               get_state_val(PART:"red_circle", STATE_PHYSICS_FRICTION,
                     fric);
               send_message(MSG_STRING_FLOAT_SET, 1, "Mass", mass);
               send_message(MSG_STRING_FLOAT_SET, 1, "Friction", fric);
               send_message(MSG_STRING_FLOAT_SET, 1, "Restitution", rest);

               get_state_val(PART:"red_circle", STATE_PHYSICS_DAMPING,
                     linear, angular);
               send_message(MSG_STRING_FLOAT_SET, 1, "Damping", linear,
                       angular);

               get_state_val(PART:"red_circle", STATE_PHYSICS_SLEEP,
                     linear, angular);
               send_message(MSG_STRING_FLOAT_SET, 1, "Sleep", linear,
                       angular);

               get_state_val(PART:"red_circle", STATE_PHYSICS_LIGHT_ON, val);
               send_message(MSG_STRING_INT, 1, "Light On", val);

               get_state_val(PART:"red_circle",
                       STATE_PHYSICS_IGNORE_PART_POS, val);
               send_message(MSG_STRING_INT, 1, "Ignore Part Pos", val);

               get_state_val(PART:"red_circle", STATE_PHYSICS_Z, val);
               send_message(MSG_STRING_INT, 1, "Z", val);

               get_state_val(PART:"red_circle", STATE_PHYSICS_DEPTH, val);
               send_message(MSG_STRING_INT, 1, "Depth", val);
            }
         }

      }

   }
}
